<?php

namespace app\components;
use \qore\base\Component;
use \app\models\Resource;
use \Qore;
use \RecursiveDirectoryIterator;
use \RecursiveIteratorIterator;
use \FilesystemIterator;

/**
 * @author Samuel Nogueira <samuel.nogueira.dev@gmail.com>
 */
class LocalRepository extends Component {
	public $directory = '.';
	public $stateFilename = '.llsync';
	protected $_allResources;
	protected $_newResources;
	protected $_savedResources;
	
	public function getStateFilePathname() {
		return $this->getDirectory().DIRECTORY_SEPARATOR.$this->getStateFilename();
	}
	
	/**
	 * Returns an array with previous saved resources
	 * @return array
	 */
	public function getSavedResources() {
		$pathname = $this->getStateFilePathname();
		
		return $this->cache('_savedResources', function() use ($pathname) {
			if (!is_file($pathname)) return array();
			
			return json_decode(
				file_get_contents($pathname)
			);
		});
	}
	
	/**
	 * Returns an array with current filesystem resources
	 * @return array
	 */
	public function getNewResources() {
		if (isset($this->_newResources)) return $this->_newResources;
		
		$resources = array();
		$iterator = new RecursiveIteratorIterator(
			new RecursiveDirectoryIterator($this->getDirectory(), FilesystemIterator::SKIP_DOTS)
		);
		
		foreach($iterator as $fileInfo) {
			$resource = $this->_createResource($fileInfo);
			$resources[$resource->getId()] = $resource;
		}
		
		return $this->_newResources = $resources;
	}
	
	/**
	 * Returns an array with the computed differences between current filesystem
	 * and previous saved resources
	 * @return array
	 */
	public function getAllResources() {
		if (isset($this->_allResources)) return $this->_allResources;
		
		$resources = array();
		
		// fetch new resources
		foreach(array_diff_key($this->getNewResources(), $this->getSavedResources()) as $resource) {
			/* @var \app\models\Resource */
			$resource->setStatus(Resource::STATUS_NEW);
			$resources[$resource->getId()] = $resource;
		}
		
		// fetch unmodified resources
		foreach(array_intersect_key($this->getNewResources(), $this->getSavedResources()) as $resource) {
			/* @var \app\models\Resource */
			$resource->setStatus(Resource::STATUS_NOT_MODIFIED);
			$resources[$resource->getId()] = $resource;
		}
		
		// fetch deleted resources
		foreach(array_diff_key($this->getSavedResources(), $this->getNewResources()) as $resource) {
			/* @var \app\models\Resource */
			$resource->setStatus(Resource::STATUS_DELETED);
			$resources[$resource->getId()] = $resource;
		}
		
		return $this->_allResources = $resources;
	}
	
	/**
	 * Returns an array with locally changed files since last save
	 * @return array
	 */
	public function getChangedResources() {
		return array_filter($this->getAllResources(), function($resource) {
			return $resource->isChanged();
		});
	}
	
	/**
	 * Saves current resources to file
	 */
	public function saveStateToFile() {
		file_put_contents($this->getStateFilePathname(), json_encode($this->_savedState));
	}
	
	/**
	 * @param SplFileInfo $fileInfo
	 * @return \app\models\Resource
	 */
	protected function _createResource($fileInfo) {
		$resource = new Resource();
		$resource->setFileInfo($fileInfo);
		return $resource;
	}
}
